<template>
  <div
    class="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-blue-500 via-purple-600 to-pink-500 text-white p-4 relative overflow-hidden"
  >
    <!-- 动态背景（星空/粒子效果） -->
    <div class="absolute inset-0 z-0">
      <canvas ref="bgCanvas" class="w-full h-full"></canvas>
    </div>

    <!-- 标题 -->
    <h1 class="text-6xl font-extrabold mb-6 title-gradient relative z-10">🎮 碰碰球</h1>

    <!-- 游戏主容器 -->
    <div
      class="game-container relative w-[1200px] h-[800px] rounded-2xl shadow-2xl overflow-hidden z-10"
    >
      <canvas ref="canvas" class="w-full h-full"></canvas>

      <!-- 分数显示 -->
      <div class="absolute top-6 left-6 score-board">
        分数: <span class="text-red-500">{{ score }}</span>
      </div>

      <!-- 游戏结束界面 -->
      <div v-if="isGameOver" class="absolute inset-0 flex items-center justify-center">
        <div class="game-over">
          <div class="text-4xl font-bold mb-4">💀 游戏结束!</div>
          <div class="text-2xl mb-6">最终分数: {{ score }}</div>
          <button @click="resetGame(0)" class="btn">按空格键重新开始</button>
          <button @click="resetGame(2)" class="btn">困难模式</button>
          <button @click="resetGame(3)" class="btn">地狱模式</button>
        </div>
      </div>
    </div>

    <!-- 操作说明 -->
    <div class="mt-8 text-center text-xl text-white/90 max-w-[1200px] leading-relaxed z-10">
      <p>使用方向键 ← → 移动挡板，按空格键重新开始</p>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue'

// 小球速度配置
const ballSpeed = ref(5)

// 游戏状态类型
interface GameState {
  ball: {
    x: number
    y: number
    radius: number
    dx: number
    dy: number
    color: string
    hit: boolean
  }
  paddle: {
    width: number
    height: number
    x: number
    y: number
    color: string
    speed: number
    shadowColor: string
  }
  score: number
  isGameOver: boolean
  keys: {
    left: boolean
    right: boolean
  }
}

// DOM引用
const canvas = ref<HTMLCanvasElement | null>(null)
const ctx = ref<CanvasRenderingContext2D | null>(null)

// 背景canvas
const bgCanvas = ref<HTMLCanvasElement | null>(null)
const bgCtx = ref<CanvasRenderingContext2D | null>(null)

// 游戏状态
const gameState = ref<GameState>({
  ball: {
    x: 0,
    y: 0,
    radius: 25,
    dx: 0,
    dy: 0,
    color: '#f97316',
    hit: false
  },
  paddle: {
    width: 180,
    height: 20,
    x: 0,
    y: 0,
    color: '#10b981',
    speed: 12,
    shadowColor: 'rgba(16, 185, 129, 0.5)'
  },
  score: 0,
  isGameOver: false,
  keys: {
    left: false,
    right: false
  }
})

// 简化访问
const score = ref(0)
const isGameOver = ref(false)
let animationFrameId: number | null = null

// 音效
const sounds = {
  wallHit: new Audio('/audio/pengzhuang.mp3'),
  paddleHit: new Audio('/audio/good.mp3'),
  gameOver: new Audio('/audio/fail.mp3')
}

const playSound = (audio: HTMLAudioElement) => {
  audio.currentTime = 0
  audio.play().catch(() => {})
}

// 绘制球
const drawBall = () => {
  if (!ctx.value) return
  const { ball } = gameState.value

  ctx.value.save()
  if (ball.hit) {
    ctx.value.shadowBlur = 20
    ctx.value.shadowColor = ball.color
  }
  ctx.value.beginPath()
  ctx.value.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2)
  ctx.value.fillStyle = ball.color
  ctx.value.fill()
  ctx.value.closePath()
  ctx.value.restore()

  if (ball.hit) {
    setTimeout(() => {
      ball.hit = false
    }, 200)
  }
}

// 绘制挡板
const drawPaddle = () => {
  if (!ctx.value) return
  const { paddle } = gameState.value
  ctx.value.beginPath()
  ctx.value.rect(paddle.x, paddle.y, paddle.width, paddle.height)
  const gradient = ctx.value.createLinearGradient(
    paddle.x,
    paddle.y,
    paddle.x + paddle.width,
    paddle.y
  )
  gradient.addColorStop(0, '#10b981')
  gradient.addColorStop(1, '#3b82f6')
  ctx.value.fillStyle = gradient
  ctx.value.shadowBlur = 15
  ctx.value.shadowColor = paddle.shadowColor
  ctx.value.fill()
  ctx.value.closePath()
  ctx.value.shadowBlur = 0
}

// 更新
const update = () => {
  if (!ctx.value || !canvas.value) return
  const { ball, paddle, keys } = gameState.value
  ctx.value.clearRect(0, 0, canvas.value.width, canvas.value.height)

  drawBall()
  drawPaddle()
  score.value = gameState.value.score

  if (gameState.value.isGameOver) {
    isGameOver.value = true
    return
  }

  ball.x += ball.dx
  ball.y += ball.dy

  if (ball.x + ball.radius > canvas.value.width || ball.x - ball.radius < 0) {
    ball.dx = -ball.dx
    playSound(sounds.wallHit)
  }
  if (ball.y - ball.radius < 0) {
    ball.dy = -ball.dy
    playSound(sounds.wallHit)
  }
  if (ball.y + ball.radius > canvas.value.height) {
    gameState.value.isGameOver = true
    playSound(sounds.gameOver)
  }

  if (
    ball.x + ball.radius > paddle.x &&
    ball.x - ball.radius < paddle.x + paddle.width &&
    ball.y + ball.radius > paddle.y &&
    ball.y - ball.radius < paddle.y + paddle.height
  ) {
    ball.dy = -ballSpeed.value
    gameState.value.score++
    ball.hit = true
    playSound(sounds.paddleHit)
    const hitPosition = (ball.x - paddle.x) / paddle.width
    ball.dx = ballSpeed.value * 1.6 * (hitPosition - 0.5) * 2
  }

  if (keys.left && paddle.x > 0) {
    paddle.x -= paddle.speed
  } else if (keys.right && paddle.x < canvas.value.width - paddle.width) {
    paddle.x += paddle.speed
  }

  animationFrameId = requestAnimationFrame(update)
}

// 重置游戏
const resetGame = (mode: number = 0) => {
  if (animationFrameId) cancelAnimationFrame(animationFrameId)
  if (!canvas.value) return

  if (mode === 0) ballSpeed.value = 5
  else if (mode === 1) ballSpeed.value = 7
  else if (mode === 2) ballSpeed.value = 9
  else if (mode === 3) ballSpeed.value = 12

  gameState.value.ball.dx = ballSpeed.value * (Math.random() > 0.5 ? 1 : -1)
  gameState.value.ball.dy = ballSpeed.value
  gameState.value.ball.x = canvas.value.width / 2
  gameState.value.ball.y = 80
  gameState.value.paddle.x = canvas.value.width / 2 - gameState.value.paddle.width / 2
  gameState.value.paddle.y = canvas.value.height - 40
  gameState.value.score = 0
  gameState.value.isGameOver = false
  isGameOver.value = false
  update()
}

// 控制
const handleKeyDown = (e: KeyboardEvent) => {
  if (e.key === 'ArrowLeft') gameState.value.keys.left = true
  else if (e.key === 'ArrowRight') gameState.value.keys.right = true
  else if (e.key === ' ' && gameState.value.isGameOver) resetGame()
}
const handleKeyUp = (e: KeyboardEvent) => {
  if (e.key === 'ArrowLeft') gameState.value.keys.left = false
  else if (e.key === 'ArrowRight') gameState.value.keys.right = false
}

// 背景粒子
let stars: { x: number; y: number; r: number; dx: number; dy: number }[] = []
const drawBackground = () => {
  // 将可能为null的引用赋值给局部变量
  const ctx = bgCtx.value;
  const canvas = bgCanvas.value;
  
  // 一次性检查局部变量是否为null
  if (!ctx || !canvas) return;
  
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  stars.forEach((s) => {
    // 使用局部变量，避免重复访问可能为null的引用
    ctx.beginPath();
    ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
    ctx.fillStyle = 'rgba(255,255,255,0.8)';
    ctx.fill();
    s.x += s.dx;
    s.y += s.dy;
    if (s.x < 0 || s.x > canvas.width) s.dx *= -1;
    if (s.y < 0 || s.y > canvas.height) s.dy *= -1;
  });
  requestAnimationFrame(drawBackground);
};

// 挂载
onMounted(() => {
  if (!canvas.value) return
  ctx.value = canvas.value.getContext('2d')
  canvas.value.width = 1200
  canvas.value.height = 800

  gameState.value.ball.x = canvas.value.width / 2
  gameState.value.ball.y = 80
  gameState.value.paddle.x = canvas.value.width / 2 - gameState.value.paddle.width / 2
  gameState.value.paddle.y = canvas.value.height - 40

  window.addEventListener('keydown', handleKeyDown)
  window.addEventListener('keyup', handleKeyUp)

  // 背景初始化
  if (bgCanvas.value) {
    bgCtx.value = bgCanvas.value.getContext('2d')
    bgCanvas.value.width = window.innerWidth
    bgCanvas.value.height = window.innerHeight
    stars = Array.from({ length: 80 }, () => ({
      x: Math.random() * bgCanvas.value!.width,
      y: Math.random() * bgCanvas.value!.height,
      r: Math.random() * 2 + 1,
      dx: (Math.random() - 0.5) * 0.5,
      dy: (Math.random() - 0.5) * 0.5
    }))
    drawBackground()
  }

  resetGame()
})

onUnmounted(() => {
  if (animationFrameId) cancelAnimationFrame(animationFrameId)
  window.removeEventListener('keydown', handleKeyDown)
  window.removeEventListener('keyup', handleKeyUp)
})
</script>

<style scoped lang="scss">
/* 渐变标题 */
.title-gradient {
  background: linear-gradient(90deg, #ff7eb3, #ff758c, #ff7eb3);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-size: 200% auto;
  animation: shine 3s linear infinite;
}
@keyframes shine {
  0% {
    background-position: 0% 50%;
  }
  100% {
    background-position: 200% 50%;
  }
}

/* 游戏容器玻璃拟态 */
.game-container {
  background: rgba(255, 255, 255, 0.12);
  border: 2px solid rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(20px);
}

/* 分数卡片 */
.score-board {
  font-size: 1.5rem;
  font-weight: bold;
  padding: 8px 20px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.85);
  color: #222;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
}

/* 游戏结束界面 */
.game-over {
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(10px);
  padding: 40px 60px;
  border-radius: 20px;
  text-align: center;
  animation: fadeIn 0.5s ease-out;
}
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* 按钮美化 */
.btn {
  display: block;
  width: 220px;
  margin: 12px auto;
  padding: 14px 28px;
  border-radius: 12px;
  font-size: 1.2rem;
  font-weight: bold;
  background: linear-gradient(135deg, #00c6ff, #0072ff);
  color: white;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
  transition: transform 0.2s, box-shadow 0.3s;
}
.btn:hover {
  transform: translateY(-3px) scale(1.05);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
</style>
